library(tidyverse)
library(lubridate)
library(rvest)

Se importa la tabla “Compustat Global Daily” con los tipos de datos correctos.

global_daily <- read_csv("Compustat_Global_Daily.csv",
  col_types = cols(
    sedol = col_character(), 
    datadate = col_date(format = "%Y%m%d") 
  )
)

Extraemos de Wikipedia la tabla de códigos GICS con sus respectivos nombres.

gics_table <- read_html("https://en.wikipedia.org/wiki/Global_Industry_Classification_Standard") %>%
  html_node("table") %>%
  html_table(fill = TRUE) %>%
  as_tibble(.name_repair = "universal") %>%
  distinct(gsector = Sector...1, gics_name = Sector...2)

Se le añaden los nombres de los sectores a la tabla original

global_daily <- left_join(global_daily, gics_table, by = "gsector")
global_daily <- global_daily %>% 
  arrange(datadate) %>% 
  mutate(id = row_number())

Tipo de variable de cada columna

global_daily %>%
  summarise_all(class) %>%
  pivot_longer(everything(), names_to = "column", values_to = "type")

Exploratory analysis

Podemos notar que tenemos una tablas con 784102 filas y 21 columnas.

¿Cuántos valores distintos hay por cada columna? y ¿ Cuántos NA hay en cada columna?

global_daily %>% 
  summarise_all(n_distinct)
global_daily %>%
  summarise_all(~ sum(is.na(.x)))

Deberá llamarnos la atención que no hay correspondencia uno a uno entre conm y gvkey, por lo que suponemos que un conm tiene 2 gvkey, pues hay 292 gvkey y 291 conm Veamos…

global_daily %>% 
  select(gvkey, conm) %>% 
  group_by(conm) %>% 
  summarise(distinct_key = n_distinct(gvkey)) %>% 
  filter(distinct_key > 1)

Caso Nacional Financiera

Efectivamente es “NACIONAL FINANCIERA SNC” quien tiene asociados dos gvkey distintos. Veamos cuales son

global_daily %>% 
  filter(conm == "NACIONAL FINANCIERA SNC") %>% 
  group_by(gvkey) %>% 
  summarise(n = n(), prim_ap = min(datadate), ult_ap = max(datadate))

Lo que nos hace suponer que desde agosto de 2018 coexisten los dos gvkey, por lo que tendría que haber más de un registro por día

global_daily %>% 
  filter(conm == "NACIONAL FINANCIERA SNC") %>% 
  group_by(datadate) %>% 
  summarise(n = n()) %>% 
  filter(datadate >= "2013-08-07", datadate <= "2019-11-26")

Efectivamente cada día hay dos registros cada uno con diferente gvkey. Tomemos de muestra al 2019.

global_daily %>% 
  mutate(year = year(datadate)) %>% 
  filter(conm == "NACIONAL FINANCIERA SNC", year == 2019) %>% 
  select(gvkey, datadate, conm, ) %>% 
  arrange(datadate)

¡¿Qué hacemos?! ¿Quitamos los 1,645 registros de gvkey 315924?


Siguiendo con el análisis… Vemos que hay cinco diferentes monedas curcddy cinco diferentes mercados exchg. Donde el código 208 corresponde a la bolsa mexicana y que tiene 708,038 que coinciden con la suma de los registros con las monedas MXP, MXN y los NA. Así que todos los registros que no sean exchg = 208 son candidatos a eliminación

global_daily %>% 
  count(curcdd) 
global_daily %>% 
  count(exchg)
global_daily %>%
  count(curcdd) %>%
  filter(curcdd == "MXN" | curcdd == "MXP" | is.na(curcdd)) %>%
  summarise(sum(n)) %>%
  pull()
## [1] 708038

observaciones de cada compañía

global_daily %>% 
  count(conm) %>% 
  arrange(n)
global_daily %>% 
  count(conm) %>% 
  arrange(n) %>% 
  filter(n == 1)
global_daily %>% 
  select(conm, datadate) %>% 
  group_by(conm) %>%
  mutate(n = n()) %>% 
  filter(n == 1)

¿Cuántas empresas hay por sector?

global_daily %>% 
  group_by(gics_name) %>% 
  summarise(n = n_distinct(conm))
global_daily %>% 
  filter(conm == "WAL MART DE MEXICO SA") %>% 
  mutate(year = year(datadate)) %>% 
  group_by(year) %>% 
  summarise(n = n())
global_daily %>% 
  filter(conm == "WAL MART DE MEXICO SA") %>%  
  mutate(year = year(datadate)) %>% 
  filter(year == 1993) %>% 
  arrange(datadate) %>% 
  select(gvkey, datadate, conm, ajexdi, cshoc, prccd, prcstd, isin)

Se comienza a limpiar

# Se eliminan los registros que no correspondan al código de mercado de la BMV, así
# como el registro restante en USD 
global_daily1 <- global_daily %>% 
  filter(exchg == 208, !curcdd %in% "USD")

# Solo quedan registros en MXP, MXN y NA
global_daily1 %>% 
  count(curcdd)
# Se procede a ver cuales son los registros que tiene NA es moneda
curcdd_na <- global_daily1 %>% 
  filter(is.na(curcdd)) %>% 
  arrange(datadate) %>% 
  mutate(dummy = paste(as.character(datadate), conm)) %>% 
  pull(dummy)

rep_curr <- global_daily1 %>% 
  mutate(dummy = paste(as.character(datadate), conm)) %>% 
  filter(dummy %in% curcdd_na) %>% 
  arrange(datadate) %>% 
  filter(curcdd == "MXN") %>% 
  pull(dummy)

filter_out <-  global_daily1 %>% 
  mutate(dummy = paste(as.character(datadate), conm)) %>% 
  filter(dummy %in% rep_curr & is.na(curcdd)) %>% 
  arrange(datadate) %>% 
  pull(id)

global_daily1 <- global_daily1 %>% 
  filter(!id %in% filter_out)

global_daily1 %>% 
  count(curcdd)
elim <- global_daily1 %>% 
  filter(is.na(curcdd)) %>% 
  pull(id)

global_daily1 <- global_daily1 %>% 
  filter(!id %in% elim)
global_daily1 %>%
  summarise_all(~ sum(is.na(.x)))

Todas las empresas que tienen alguna fecha duplicada

filt_dup <- global_daily1 %>% 
  group_by(datadate, conm) %>% 
  count(datadate) %>% 
  filter(n > 1)  %>% 
  mutate(dummy = paste(as.character(datadate),conm)) %>% 
  pull(dummy)

dups <- global_daily1 %>%
  mutate(dummy = paste(as.character(datadate), conm)) %>%
  filter(dummy %in% filt_dup) %>%
  arrange(datadate) %>%
  select(-dummy)

dups 

¿Cuántas empresas diferentes tienen duplicados?

length(unique(dups$conm))
## [1] 72
unique(dups$conm)
##  [1] "TUBOS DE ACERO DE MEXICO"     "TELMEX-TELEFONOS DE MEXICO"  
##  [3] "WAL MART DE MEXICO SA"        "INDUSTRIAS PENOLES SAB DE CV"
##  [5] "KIMBERLY-CLARK DE MEXICO SA"  "GRUPO MEXICO SAB DE CV"      
##  [7] "ALFA SAB DE CV"               "GRUPO BIMBO SA DE CV"        
##  [9] "CEMEX SAB DE CV"              "BCO NAC MEXICO"              
## [11] "GRUPO INDUSTRIAL MASECA"      "TELEINDUSTRIA ERICCSON SA"   
## [13] "GRUPO FINANCIERO SERFIN SA"   "GRUPO KUO SAB DE CV"         
## [15] "GRUPO FINANCIERO BANAMEX ACC" "GRUPO TMM S.A.B"             
## [17] "SYNKRO SA DE CV"              "GRUPO SIDEK SA DE CV"        
## [19] "GRUPO TELEVISA SAB"           "GRUPO CONDUMEX SA DE CV"     
## [21] "GPO FINANCIERO BBVA BANCOMER" "GRUPO CARSO SA DE CV"        
## [23] "CONTROLADORA COMERCIAL MEX"   "INDUSTRIAS NACOBRE SA DE CV" 
## [25] "AEROVIAS DE MEXICO SA DE CV"  "RASSINI SAB DE CV"           
## [27] "APASCO SA DE CV"              "EL PUERTO DE LIVERPOOL SA"   
## [29] "ALUMSA ALUMINIO SA DE CV"     "GRUPO INDUSTRIAL SALTILLO"   
## [31] "GRUPO POSADAS SAB DE CV"      "INTL DE CERAMICA SA DE CV"   
## [33] "EMPAQUES PONDEROSA SA"        "GRUPO HERDEZ SAB DE CV"      
## [35] "ORGANIZACION CULTIBA SAB DE"  "GRUPO MEXICANO DESARROLLO"   
## [37] "PEPSI-GEMEX SA DE CV"         "ACCEL SAB DE CV"             
## [39] "CIA MINERA AUTLAN SA DE CV"   "GRUPO IUSACELL SA"           
## [41] "GPO FIN INVERMEXIC"           "SAN CRISTOBAL SA"            
## [43] "GRUPO FINANCIERO INBURSA SA"  "SISTEMA AXIS SA"             
## [45] "GRUPO FINANCIERO BANORTE SA"  "GRUPO FINANCIERO BANCRECER"  
## [47] "GRUPO ELEKTRA SA DE CV"       "CASA DE BOLSA FINAMEX SAB DE"
## [49] "GRUPO SANBORN SA DE CV"       "EDITORIAL DIANA SA DE CV"    
## [51] "GRUPO PALACIO DE HIERRO"      "ORBIA ADVANCE CORP SAB DE CV"
## [53] "VALORES MONTERREY AETNA SA"   "REGIO EMPRESAS SA DE CV"     
## [55] "MAQUINARIA DIESEL SA DE CV"   "GRUPO MACMA SA DE CV"        
## [57] "SOCIEDAD ELECTROMECANICA SA"  "GRUPO RADIO CENTRO SA DE CV" 
## [59] "FOMENTO ECONOMICO MEXICANO"   "GRUPO ICONSA SA DE CV"       
## [61] "INTERAMERICANA ENTRTENMIENTO" "AMERICA MOVIL SA DE CV"      
## [63] "CONSORCIO G GRUPO DINA SA"    "GENERAL DE SEGUROS SAB"      
## [65] "HYLSAMEX SA DE CV"            "CYDSA SA"                    
## [67] "DINE S.A.B. DE C.V."          "TELMEX INTERNACIONAL SAB DE" 
## [69] "BIO PAPPEL SAB DE CV"         "NACIONAL FINANCIERA SNC"     
## [71] "PROMOTORA Y OPERADORA INFRAE" "TELESITES SAB DE CV"
cshoc_na <- dups %>% 
  filter(is.na(cshoc)) %>% 
  mutate(dummy = paste(as.character(datadate), conm)) %>% 
  pull(dummy)

dups %>% 
  mutate(dummy = paste(as.character(datadate), conm)) %>%
  filter(dummy %in% cshoc_na) 
dups %>% 
  mutate(dummy = paste(as.character(datadate), conm)) %>%
  filter(dummy %in% cshoc_na) %>%  
  group_by(datadate, conm) %>% 
  summarise(sin_na = sum(!is.na(cshoc)), con_na = sum(is.na(cshoc))) 
elim2 <- dups %>% 
  mutate(dummy = paste(as.character(datadate), conm)) %>%
  filter(dummy %in% cshoc_na, is.na(cshoc)) %>% 
  pull(id)
global_daily1 <- global_daily1 %>% 
  filter(!id %in% elim2)
dups <- global_daily1 %>%
  mutate(dummy = paste(as.character(datadate), conm)) %>%
  filter(dummy %in% filt_dup) %>%
  arrange(datadate) %>%
  select(-dummy)

dups %>% 
  summarise_all(~ sum(is.na(.x)))
dups %>% 
  mutate(mv = cshoc * prccd)